<template>
    <div class="sky-container" :style="{width: `${props.width}px`, height: `${props.width}px`}" >
        <canvas id="skymapCanvas" style="width: 100%; height: 100%;"></canvas>
        <div class="stBox" :style="{fontSize: `${props.scale * 1.9}em`, top: `${props.scale * 15}px`, left: `${props.scale * 15}px`}" >
            <div>本地恒星时</div>
            <div class="st ldNum"> {{siderealTimeStr}} </div>
        </div>
        <div class="loc" v-show="props.setting.showLonLat" :style="{fontSize: `${props.scale * 0.9}em`}">
            <div>{{props.setting.longitude}}°E</div>
            <div>{{props.setting.latitude}}°N</div>
        </div>
    </div>
</template>

<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { calHipAltAzi, getHipData, getMoonPos, getSunPos } from '../api';
import type { HipData, HipDataExtend } from '../api';
import { getPlanetPosition, HoursMinutesSeconds, JulDay, LM_Sidereal_Time, re2azi } from '../api/calc';
import type { Setting } from  '../App.vue'

const props = defineProps<{
    scale: number,
    time: Date,
    setting: Setting,
    width: number,
}>();

const dpr = ref(window.devicePixelRatio || 1);
const moonImg = new URL("../assets/moon.png", import.meta.url);
const imgLoaded = ref(false);
const img = new Image();
img.src = moonImg.href;
img.onload = () => {
    imgLoaded.value = true;
};


const draw = (canvas: HTMLCanvasElement, hipData: HipDataExtend) => {

    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    const longitude = props.setting.longitude;
    const latitude = props.setting.latitude;

    const width = canvas.clientWidth * dpr.value;
    const height = canvas.clientHeight * dpr.value;
    const scale = props.scale * dpr.value;
    canvas.width = width;
    canvas.height = height;
    ctx.clearRect(0, 0, width, height);
    ctx.fillStyle = '#000';
    ctx.fillRect(0, 0, width, height);

    const x0 = width / 2;
    const y0 = height / 2;
    const R = Math.min(width, height) / 2 - 30*scale;

    ctx.strokeStyle = '#fff';
    ctx.lineWidth = 2 * scale;
    ctx.beginPath();
    ctx.arc(x0, y0, R, 0, Math.PI * 2);
    ctx.stroke();

    // 画中心十字坐标轴
    ctx.lineWidth = 0.8 * scale;
    ctx.strokeStyle = '#888';
    ctx.beginPath();
    ctx.moveTo(x0, y0 - R);
    ctx.lineTo(x0, y0 + R);
    ctx.moveTo(x0-R, y0);
    ctx.lineTo(x0+R, y0);
    ctx.stroke();
    Array(1/9, 3/9, 5/9, 7/9).forEach((i) => {
        const r = R * i as number;
        ctx.beginPath();
        ctx.arc(x0, y0, r, 0, Math.PI * 2);
        ctx.stroke();
    });
    // 中间写上天顶
    ctx.fillStyle = '#ffffff88';
    ctx.font = `${16 * (scale * 0.8+0.2)}px Arial`;
    ctx.fillText('天顶', x0 - ctx.measureText('天顶').width / 2, y0 + 5);

    const altazi2xy = (alt: number, azi: number) => {
        const r = R * (1 - alt / (Math.PI / 2));
        return {
            x: x0 + Math.sin(azi) * r,
            y: y0 + Math.cos(azi) * r
        };
    };

    const text = (x: number, y: number, content: string, size: number=14) => {
        ctx.fillStyle = '#DDD';
        ctx.font = `${size*(scale*0.8+0.2)}px Arial`;
        ctx.fillText(content, x, y + size / 2);
    };

    for(let i = 0; i < hipData.RA.length ; i++) {
        if(hipData.alt[i] < 0) continue; // 只画在地平线以上的恒星
        const azi = hipData.azi[i] // 将RA从小时转换为弧度
        const alt = hipData.alt[i]; // 将DEC从度转换为弧度
        const m = 1.4 ** (-hipData.Mag[i]) * 4;
        const xy = altazi2xy(alt, azi);
        ctx.fillStyle = '#fff';
        if(hipData.Mag[i] < 3){
            const glowSize = m * 3 * scale  // Bigger glow for brighter stars
            const gradient = ctx.createRadialGradient(xy.x, xy.y, m, xy.x, xy.y, glowSize);
            gradient.addColorStop(0, 'rgba(255, 255, 255, 1)');
            gradient.addColorStop(0.2, 'rgba(255, 255, 255, 0.5');
            gradient.addColorStop(1, 'rgba(255, 255, 255, 0)');

            ctx.beginPath();
            ctx.arc(xy.x, xy.y, glowSize, 0, Math.PI * 2);
            ctx.fillStyle = gradient;
            ctx.fill();
        }
        else{
            ctx.beginPath();
            ctx.arc(xy.x, xy.y, m*scale, 0, Math.PI * 2);
            ctx.fillStyle = '#fff';
            ctx.fill();
        }
    }

    const sunPos = getSunPos(latitude, longitude, new Date());
    if (sunPos.altitude > 0){
        const m = 16 * scale; 
        const xy = altazi2xy(sunPos.altitude, sunPos.azimuth);
        ctx.fillStyle = 'yellow';
        // Draw sun glow effect
        const gradient = ctx.createRadialGradient(xy.x, xy.y, m, xy.x, xy.y, m * 3);
        gradient.addColorStop(0, 'rgba(255, 255, 0, 1)');
        gradient.addColorStop(0.3, 'rgba(255, 165, 0, 0.7)');
        gradient.addColorStop(0.7, 'rgba(255, 69, 0, 0.4)');
        gradient.addColorStop(1, 'rgba(255, 0, 0, 0)');

        ctx.beginPath();
        ctx.arc(xy.x, xy.y, m * 3, 0, Math.PI * 2);
        ctx.fillStyle = gradient;
        ctx.fill();

        // Draw the sun core
        ctx.fillStyle = 'yellow';
        ctx.beginPath();
        ctx.arc(xy.x, xy.y, m, 0, Math.PI * 2);
        ctx.fill();
    }

    const moonPos = getMoonPos(latitude, longitude, new Date());
    if (moonPos.altitude > 0){
        const m = 18 * scale;
        const xy = altazi2xy(moonPos.altitude, moonPos.azimuth);
        const glowSize = m * 2; // Glow size for the moon
        const gradient = ctx.createRadialGradient(xy.x, xy.y, m, xy.x, xy.y, glowSize);
        gradient.addColorStop(0, 'rgba(255, 255, 255, 1)');
        gradient.addColorStop(0.2, 'rgba(255, 255, 255, 0.4)');
        gradient.addColorStop(1, 'rgba(255, 255, 255, 0)');

        ctx.beginPath();
        ctx.arc(xy.x, xy.y, glowSize, 0, Math.PI * 2);
        ctx.fillStyle = gradient;
        ctx.fill();

        if(imgLoaded.value) {
            ctx.drawImage(img, xy.x - m, xy.y - m, m * 2, m * 2);
        };


    }

    // 行星
    const time = new Date();
    const jd = JulDay(time);
    const st = LM_Sidereal_Time(jd, longitude);
    const planetPos = getPlanetPosition(time);
    planetPos.forEach(planet => {
        if (planet.name == '地') return; // 跳过地球
        const pos = re2azi(st, latitude* Math.PI / 180, 
            planet.ra, planet.dec);
        if (pos.alt < 0) return;
        const xy = altazi2xy(pos.alt, pos.azi);
        const m = 3 * scale; // 行星大小
        // Create a glowing effect for planets
        const glowSize = m * 4;  // Size of the glow
        const gradient = ctx.createRadialGradient(xy.x, xy.y, m, xy.x, xy.y, glowSize);
        gradient.addColorStop(0, 'rgba(255, 165, 0, 1)');    // Orange at center
        gradient.addColorStop(0.5, 'rgba(255, 140, 0, 0.6)'); // Darker orange
        gradient.addColorStop(1, 'rgba(255, 69, 0, 0)');     // Fade to transparent red
        // Draw the glow
        ctx.beginPath();
        ctx.arc(xy.x, xy.y, glowSize, 0, Math.PI * 2);
        ctx.fillStyle = gradient;
        ctx.fill();
        // Draw the planet core
        ctx.fillStyle = 'orange';
        ctx.beginPath();
        ctx.arc(xy.x, xy.y, m, 0, Math.PI * 2);
        ctx.fill();

        // Write the planet name
        text(xy.x + m + 8, xy.y, planet.name, 14);
    });



    // 东南西北
    const directions = ['东', '南', '西', '北'];
    const directionAngles = [0, Math.PI / 2, Math.PI, 3 * Math.PI / 2];
    ctx.fillStyle = '#fff';
    ctx.font = `${16 * (scale*0.8+0.2)}px Arial`;
    directions.forEach((dir, index) => {
        const angle = directionAngles[index];
        const x = x0 + Math.cos(angle) * (R + 15);
        const y = y0 + Math.sin(angle) * (R + 15);
        ctx.fillText(dir, x - ctx.measureText(dir).width / 2, y + 8);
    });

}

// ================ 其他内容 ================
const siderealTimeStr = ref('');


let hip: HipData | null = null;
let cavans: HTMLCanvasElement | null = null;

const updateSiderealTime = () => {
    const time = new Date();
    siderealTimeStr.value = HoursMinutesSeconds(LM_Sidereal_Time(JulDay(time), props.setting.longitude));
}

const updateSkyMap = () => {
    if (!hip || !cavans) return;
    const time = new Date();
    const hipData = calHipAltAzi(hip, time, props.setting.latitude, props.setting.longitude);
    draw(cavans, hipData);
}

let siderealTimeTimer = 0;
let skyMapTimer = 0;

onMounted(async () => {
    hip = await getHipData();
    cavans = document.getElementById('skymapCanvas') as HTMLCanvasElement;
    updateSiderealTime();
    updateSkyMap();
    skyMapTimer = setInterval(updateSkyMap, props.setting.skyMapInterval * 1000);
    siderealTimeTimer = setInterval(updateSiderealTime, props.setting.clockInterval * 1000);
})

watch(() => props.setting, () => {
    if (siderealTimeTimer) {
        clearInterval(siderealTimeTimer);
    }
    if (skyMapTimer) {
        clearInterval(skyMapTimer);
    }
    updateSiderealTime();
    updateSkyMap();
    siderealTimeTimer = setInterval(updateSiderealTime, props.setting.clockInterval * 1000);
    skyMapTimer = setInterval(updateSkyMap, props.setting.skyMapInterval * 1000);
}, { deep: true, immediate: true });

watch(() => props.width, ()=>{
    updateSkyMap();
}, { immediate: true})

onBeforeUnmount(() => {
    if (siderealTimeTimer) {
        clearInterval(siderealTimeTimer);
    }
    if (skyMapTimer) {
        clearInterval(skyMapTimer);
    }
})

</script>
<style scoped>

.sky-container {
    position: relative;
    height: 100%;
    aspect-ratio: 1 / 1;
    width: auto;
}
@media screen and (max-width: 768px) {
    .sky-container {
        width: 100%;
        height: auto;
    }
}

#skymapCanvas {
    background: #000;
    display: block;
    position: absolute;
    top: 0;
    left: 0;
}
.st{
    color: #fff;
    font-size: 1.6em;
    letter-spacing: 0.05em;
}
.stBox{
    position: absolute;
    top: 15px;
    left: 15px;
    z-index: 10;
}
.loc{
    position: absolute;
    bottom: 55px;
    left: 15px;
    z-index: 10;
    font-family: 'Fira Code', monospace;
}

@media screen and (max-width: 768px) {
    .loc{
        left: auto;
        right: 15px;
        bottom: 15px;
    }
}
</style>
